package com.uci.scheduleshare;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.List;

import com.bump.api.BumpAPIIntents;
import com.bump.api.IBumpAPI;
import com.uci.scheduleshare.adapters.*;
import com.uci.scheduleshare.calendar.*;
import com.uci.scheduleshare.calendardb.*;
import com.viewpagerindicator.*;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
import android.provider.Settings;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;


/**
 * CS 190 Spring 2012
 * ScheduleShareActivity.java
 * The main activity for the application. 
 * Creates all the adapters, database access objects, and Bump API
 * 
 * @author Patrick Hsu, Lauren Ko, Pomi Park
 *
 */
public class ScheduleShareActivity extends Activity {
	
	private static final int SETTINGS_CODE = 0;
	
	// Bump
	private IBumpAPI api;
	private Boolean bumpToggle;
	private Boolean bumpConnected;
	private ServiceConnection connection;
	private BroadcastReceiver receiver;
	
	// Database Access Objects
	private CalendarDBAdapter dbAdapter;
	private CalendarDatabase calendarDB;
	private DBApplication dbApp;
	
	// User's default calendar
	private String defaultCalendarID;
	
	private List<Contact> contacts;
	private List<String> activities;
	
	private SharedPreferences myPrefs;
	
	// Adapters
	private ContactsAdapter contactsAdapter;
	private ViewPagerAdapter viewPagerAdapter;
	private RecentActivityAdapter activityAdapter;
	
	// Data to be sent through Bump
	private Contact mContact;
	
	// UI colors
	private int footerColor = 0xFF37b415;
	private int titleBackgroundColor = 0xFF3c3c3c;
	
	private LinearLayout bumpToggleLayout;
	private TextView toggleText;
	
	List<Event> myEvents;
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		setContentView(R.layout.main);
		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_bar);
	    // Preferences
	    myPrefs = getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
	    defaultCalendarID = myPrefs.getString("default_calendar", "1");
	    
	    // Bump toggle
	    bumpToggleLayout = (LinearLayout)findViewById(R.id.bump_toggle);
	    toggleText = (TextView)findViewById(R.id.bump_toggle_text);
	    toggleText.setTextAppearance(getApplicationContext(), R.style.ToggleOffText);
	    toggleText.setText("OFF");
	    bumpToggleLayout.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				bumpDevice();
			}
		});
	    
		// Database object creation
		dbApp = (DBApplication)getApplication();
		if(dbApp.getDbAdapter() == null) {
			dbAdapter = new CalendarDBAdapter(this);
			dbApp.setDbAdapter(dbAdapter);
		} else {
			dbAdapter = dbApp.getDbAdapter();
		}
		calendarDB = new CalendarDatabase(this, CalendarDatabase.DB_NAME, null, CalendarDatabase.DB_VERSION);
		
		// Create contact for self
		mContact = dbAdapter.createContact(defaultCalendarID);
		int myColor = myPrefs.getInt("color", 0x800000FF);
		mContact.setColor(myColor);
		
		// Populate the contacts and activities lists
		contacts = calendarDB.getAllContacts();
		contacts.add(0, mContact);
	    activities = calendarDB.getRecentActivity();
	    
	    // Adapters
		contactsAdapter = new ContactsAdapter(contacts, this, calendarDB, myPrefs);
		activityAdapter = new RecentActivityAdapter(this, activities);
		viewPagerAdapter = new ViewPagerAdapter(this, contacts, activities, contactsAdapter, activityAdapter, calendarDB);
		ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
		TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.indicator);
		indicator.setFooterColor(footerColor);
		indicator.setBackgroundColor(titleBackgroundColor);
		indicator.setSelectedBold(true);
		pager.setAdapter(viewPagerAdapter);
		indicator.setViewPager(pager);
		
		// For allowing Bump network access 
		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy); 
		
		// Bump stuff
		bumpToggle = false;
		bumpConnected = false;	  
	}

	// MENU BUTTON //
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, SETTINGS_CODE, 0, "Settings"); // Adding a "Settings" option
		return super.onCreateOptionsMenu(menu);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if(item.getItemId() == SETTINGS_CODE) {
			// Start the SettingsActivity class
			startActivityForResult(new Intent(this, SettingsActivity.class), SETTINGS_CODE);
		}
		return super.onOptionsItemSelected(item);
	};
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if(requestCode == SETTINGS_CODE && resultCode == Activity.RESULT_OK) {
			// Once preferences have changed, set the new default calendar id
			String newDefaultCalendarID = data.getStringExtra("defaultCalendarID");
			defaultCalendarID = newDefaultCalendarID;
			Contact myNewContact = dbAdapter.createContact(defaultCalendarID);
			mContact = myNewContact;
			int myColor = myPrefs.getInt("color", 0x800000FF);
			mContact.setColor(myColor);
			// Remove the old contact from the contacts list and add the new one
			for(int i = 0; i < contacts.size(); i++) {
				if(contacts.get(i).isMe()) {
					contacts.remove(i);
					contacts.add(i, mContact);
					contactsAdapter.notifyDataSetChanged();
				}
			}
		}
	}

	    @Override
	    public void onConfigurationChanged(Configuration newConfig) {
	      super.onConfigurationChanged(newConfig);
	    }

	    public void onStart() {
	        Log.i("ScheduleShare", "onStart");
	        mContact = dbAdapter.createContact(defaultCalendarID);
	        int myColor = myPrefs.getInt("color", 0x800000FF);
			mContact.setColor(myColor);
	        contacts.remove(0);
	        contacts.add(0, mContact);
	        super.onStart();
	     }
	     
	     public void onRestart() {
	        Log.i("ScheduleShare", "onRestart");
	        super.onRestart();
	     }

	     public void onResume() {
	        Log.i("ScheduleShare", "onResume");
	        super.onResume();
	     }

	     public void onPause() {
	        Log.i("ScheduleShare", "onPause");
	        super.onPause();
	     }

	     public void onStop() {
	        Log.i("ScheduleShare", "onStop");
	        super.onStop();
	     }

	     public void onDestroy() {
	        Log.i("ScheduleShare", "onDestroy");
	       if(connection != null) {
	    	   unbindService(connection);
	       }
	       if(receiver != null){ unregisterReceiver(receiver);}
	        if(calendarDB != null) {
	        	calendarDB.close();
	        }
	        super.onDestroy();
	     }
	     
	     public void bumpDevice() {
	    	 LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
	    	 ConnectivityManager conMgr =  (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
	    	 NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo();
	    	 String toastString = "";
	 	    if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && activeNetwork != null && activeNetwork.getState() == NetworkInfo.State.CONNECTED ) {
	 	    	if(bumpToggle == false) {
	 	    		bumpToggle = true;
	 	    		toastString = "Bump enabled. Bump now!";
		 	    	if(connection == null || receiver == null) {
		 	    		createAndBindBump();
		 	    	}
		 		    if(bumpConnected) {
		 		    	try {
							api.enableBumping();
						} catch (RemoteException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
		 		    }
		 		    toggleText.setTextAppearance(getApplicationContext(), R.style.ToggleOnText);
		 		    toggleText.setText("ON");
	 	    	} else {
	 	    		bumpToggle = false;
	 	    		toastString = "Bump disabled.";
	 	    		if(bumpConnected) {
	 	    			try {
							api.disableBumping();
						} catch (RemoteException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
	 	    		}
		 	   	    toggleText.setTextAppearance(getApplicationContext(), R.style.ToggleOffText);
		 		    toggleText.setText("OFF");
	 	    	}	
	 	    } else {
	 	    	if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && activeNetwork != null && activeNetwork.getState() == NetworkInfo.State.CONNECTED) {
	 	    		toastString = "GPS not enabled. Please turn on GPS.";
	 	    	} else if ((activeNetwork == null || activeNetwork.getState() != NetworkInfo.State.CONNECTED) && locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
	 	    		toastString = "Network not enabled. Please turn on network.";
	 	    	} else {
	 	    		toastString = "Network and GPS not enabled. Please enable network and GPS.";
	 	    	}
	 	    }
 	    	LayoutInflater inflater = getLayoutInflater();
 	    	View toastLayout = inflater.inflate(R.layout.toast_layout, (ViewGroup)findViewById(R.id.toast_layout_root));
 	    	TextView toastText = (TextView) toastLayout.findViewById(R.id.toast_text);
 	    	toastText.setText(toastString);
 	    	Toast bumpToast = new Toast(getApplicationContext());
 	    	bumpToast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
 	    	bumpToast.setDuration(Toast.LENGTH_LONG);
 	    	bumpToast.setView(toastLayout);
 	    	bumpToast.show();
	 	  
	     }
	     
	     public void createAndBindBump(){
	    	 /**
	    	  * Create a new ServiceConnection to connect to the Bump servers
	    	  */
	    	 	   connection = new ServiceConnection() {
	    	 	   	        @Override
	    	 	   	        public void onServiceConnected(ComponentName className, IBinder binder) {
	    	 	   	            Log.i("ScheduleShare", "onServiceConnected");
	    	 	   	            api = IBumpAPI.Stub.asInterface(binder);
	    	 	   	            try {
	    	 	   	                api.configure("18821610fbf04579814d05bb287e2856",
	    	 	   	                              "ScheduleShare User");
	    	 	   	            } catch (RemoteException e) {
	    	 	   	                Log.w("ScheduleShare", e);
	    	 	   	            }
	    	 	   	            Log.d("ScheduleShare", "Service connected");
	    	 	   	        }

	    	 	   	        @Override
	    	 	   	        public void onServiceDisconnected(ComponentName className) {
	    	 	   	            Log.d("ScheduleShare", "Service disconnected");
	    	 	   	        }
	    	 	   	    };
	    	 	/**
	    	      * Create a BroadcastReceiver - for sending and receiving Bump data
	    	      */
	    	  		receiver = new BroadcastReceiver() {
	    	  		        @Override
	    	  		        public void onReceive(Context context, Intent intent) {
	    	  		            final String action = intent.getAction();
	    	  		            try {
	    	  		                if (action.equals(BumpAPIIntents.DATA_RECEIVED)) {
	    	  		                    Log.i("ScheduleShare", "Received data from: " + api.userIDForChannelID(intent.getLongExtra("channelID", 0))); 
	    	  		                    ByteArrayInputStream bis = new ByteArrayInputStream(intent.getByteArrayExtra("data"));
	    	  		                    try {
	    	  		                    	ObjectInput in = new ObjectInputStream(bis);
	    	  		                    	try {
	    	  									Contact receiveContact = (Contact) in.readObject();
	    	  									// Add received contact to the database
	    	  									receiveContact.setID(calendarDB.addContact(receiveContact));
	    	  									receiveContact.setMe(false);
	    	  									contacts.add(receiveContact);
	    	  									// Add a new note to Recent Activity
	    	  									activities.add(calendarDB.addActivity(receiveContact.getName(), 
	    	  											receiveContact.getCalendarName(), 0));
	    	  									// notify adapters of changes
	    	  									contactsAdapter.notifyDataSetChanged();
	    	  									activityAdapter.notifyDataSetChanged();
	    	  									// Toast notification
	    	  						 	    	LayoutInflater inflater = getLayoutInflater();
	    	  						 	    	View toastLayout = inflater.inflate(R.layout.toast_layout, (ViewGroup)findViewById(R.id.toast_layout_root));
	    	  						 	    	TextView toastText = (TextView) toastLayout.findViewById(R.id.toast_text);
	    	  						 	    	toastText.setText("Bump successful! Received " + receiveContact.getName() + "'s schedule.");
	    	  						 	    	Toast bumpToast = new Toast(getApplicationContext());
	    	  						 	    	bumpToast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
	    	  						 	    	bumpToast.setDuration(Toast.LENGTH_LONG);
	    	  						 	    	bumpToast.setView(toastLayout);
	    	  						 	    	bumpToast.show();
	    	  								} catch (ClassNotFoundException e) {
	    	  									// TODO Auto-generated catch block
	    	  									e.printStackTrace();
	    	  								}
	    	  								bis.close();
	    	  								in.close();
	    	  							} catch (StreamCorruptedException e) {
	    	  								Log.d("StreamCorruptedException", e.toString());
	    	  							} catch (IOException e) {
	    	  								Log.d("IOException", e.toString());
	    	  							}

	    	  		                } else if (action.equals(BumpAPIIntents.MATCHED)) {
	    	  		                    long channelID = intent.getLongExtra("proposedChannelID", 0); 
	    	  		                    Log.i("ScheduleShare", "Matched with: " + api.userIDForChannelID(channelID));
	    	  		                    api.confirm(channelID, true);
	    	  		                    Log.i("ScheduleShare", "Confirm sent");
	    	  		                    // Successfully matched
	    	  		                } else if (action.equals(BumpAPIIntents.CHANNEL_CONFIRMED)) {
	    	  		                    long channelID = intent.getLongExtra("channelID", 0);
	    	  		                    Log.i("ScheduleShare", "Channel confirmed with " + api.userIDForChannelID(channelID));
	    	  		                    ByteArrayOutputStream bo = new ByteArrayOutputStream();
	    	  		                    ObjectOutput out;
	    	  							try {
	    	  								// Channel confirmed, write object out to byte array
	    	  								out = new ObjectOutputStream(bo);
	    	  			                    out.writeObject(mContact);
	    	  							} catch (IOException e) {
	    	  								Log.d("IOException", e.toString());
	    	  							}
	    	  		                    byte[] bytes = bo.toByteArray();
	    	  		                    api.send(channelID, bytes);

	    	  		                } else if (action.equals(BumpAPIIntents.NOT_MATCHED)) {
	    	  		                    Log.i("ScheduleShare", "Not matched.");

	    	  		                } else if (action.equals(BumpAPIIntents.CONNECTED)) {
	    	  		                    //Log.i("ScheduleShare", "Connected to Bump...");
	    	  		                    //api.enableBumping();
	    	  		                	bumpConnected = true;
	    	  		                }
	    	  		            } catch (RemoteException e) {}
	    	  		        } 
	    	  		    };
	    	  	        bindService(new Intent(IBumpAPI.class.getName()),
	    	  	                connection, Context.BIND_AUTO_CREATE);
	    	  		    Log.i("BumpTest", "boot");
	    	  		
	    	  		    IntentFilter filter = new IntentFilter();
	    	  		    filter.addAction(BumpAPIIntents.CHANNEL_CONFIRMED);
	    	  		    filter.addAction(BumpAPIIntents.DATA_RECEIVED);
	    	  		    filter.addAction(BumpAPIIntents.NOT_MATCHED);
	    	  		    filter.addAction(BumpAPIIntents.MATCHED);
	    	  		    filter.addAction(BumpAPIIntents.CONNECTED);
	    	  		    registerReceiver(receiver, filter);
	     	}
	     
	}
